<template>
  <div class="home">
    <div ref="container" class="container"></div>
    <div class="data-box">
      <div class="data" style="white-space: pre-wrap;">
        <span :class="index % 2 !== 0 ? 'hightLight' : 'common'" v-for="(item, index) in formatterData" :key="index">{{
        item
      }}</span>
      </div>
      <div style="background-color: #fff; margin-bottom: 10px;" v-show="runRes.show">
        <span>执行结果:</span><br>
        <span>步骤：</span>
        <p>{{ runRes.step }}</p>
        <span>最终上下文数据：</span>
        <p>{{ JSON.stringify(runRes.context) }}</p>
      </div>
      <el-button @click="onReq">执行规则</el-button>
    </div>
    <el-drawer v-model="config.drawerShow" title="配置" :with-header="false">
      <dynamic-form :formFields='config.formConfig' :formData="config.form" @submit="config.callback"
        @cancel="config.drawerShow = false"></dynamic-form>
    </el-drawer>

    
  </div>
  <el-dialog v-model="runParam.visiable">
      <el-input v-model="runParam.data" type="textarea"></el-input>
      <template #footer>
        <div>
          <el-button @click="">取消</el-button>
          <el-button type="primary" @click="runChain">
            确认
          </el-button>
        </div>
      </template>
  </el-dialog>
</template>
<script setup lang="ts">
import { ref, onMounted, toRaw, reactive, computed } from 'vue';
import LogicFlow from "@logicflow/core";
import "@logicflow/core/dist/style/index.css";
import '@logicflow/extension/lib/style/index.css'

import { DndPanel, SelectionSelect, Menu } from '@logicflow/extension';

import { LiteFlow, parse} from "logicflow-liteflow";
import { GraphConfigData, NodeConfig, EdgeConfig } from '@logicflow/core';
import { ELType } from "./utils/type";
import { FormConfig, getEdgeForm, parseConfig } from './utils/config';
import DynamicForm from './components/DynamicForm.vue';
import {  ElMessage } from 'element-plus';
import { LiteFlowChain } from './model/LiteFlow';
import chainService from './api/chainService';
import { nanoid } from 'nanoid';


// 声明容器的对应ref对象和LF对象
const container = ref();
const lf = ref<LogicFlow>();
const liteFlowData = ref("");

const config = reactive({
  drawerShow: false,
  formConfig: {},
  form: {} as Record<string, unknown>,
  callback: () => { }
})

const showDrawer = (formConfig: FormConfig[], properties: Record<string, unknown>, callback: () => void) => {
  config.drawerShow = true;

  config.form = properties;
  config.formConfig = formConfig;
  config.callback = callback;
}

//作为id
const getId = (): string => {
  const index = Number(localStorage.getItem("index") as string) + 1;
  localStorage.setItem("index", "" + index);
  return "n" + index;
}
if (!localStorage.getItem("index")) localStorage.setItem("index", "0");

onMounted(() => {

  lf.value = new LogicFlow({
    container: container.value,
    grid: true,
    plugins: [DndPanel, SelectionSelect, Menu, LiteFlow],
    edgeType: 'bezier',
    // 移动已有边时会有 currentEdge 信息, 否则为空
    // 逻辑节点不需要箭头
    edgeGenerator: (sourceNode, targetNode) => {
      const logics = ["AND", "OR", "NOT"]
      // 起始节点类型 rect 时使用 自定义的边 custom-edge
      if (logics.includes(sourceNode.type)) return 'custom'
      if (logics.includes(targetNode.type)) return 'custom'
    },
    textEdit: false
  })

  const icon = '';

  lf.value.extension.dndPanel.setPatternItems([
    {
      type: 'ID',
      text: '',
      label: '普通节点',
      icon,

    }, {
      type: 'IF',
      text: '',
      label: '条件节点',
      icon,
    }, {
      type: 'SWITCH',
      text: '',
      label: '选择节点',
      icon,
    }, {
      label: '分组',
      icon: '',
      callback: () => {
        lf.value?.openSelectionSelect();
        lf.value?.once('selection:selected', (elements) => {
          const nodes: NodeConfig[] = elements.filter(e => e.BaseType === "node")
          const xs: number[] = []
          const ys: number[] = []
          nodes.forEach(node => {
            xs.push(node.x - node.width / 2, node.x + node.width / 2)
            ys.push(node.y - node.height / 2, node.y + node.height / 2)
          })
          const padding = 20;
          const minX = Math.min(...xs) - padding;
          const maxX = Math.max(...xs) + padding;
          const minY = Math.min(...ys) - padding;
          const maxY = Math.max(...ys) + padding;
          const group = lf.value?.addNode({
            type: "GROUP",
            x: (minX + maxX) / 2,
            y: (minY + maxY) / 2,
            properties: {
              height: maxY - minY,
              width: maxX - minX,
              groupType: "CONFIG"
            }
          })
          nodes.forEach(node => group?.addChild(node.id))

          lf.value?.closeSelectionSelect();
        });
      }
    }, , {
      type: 'AND',
      text: '',
      label: 'AND',
      icon,
    }, {
      type: 'NOT',
      text: '',
      label: 'NOT',
      icon,
    }, {
      type: 'OR',
      text: '',
      label: 'OR',
      icon,
    }, {
      label: '选区',
      icon: '',
      callback: () => {
        lf.value?.openSelectionSelect();
        lf.value?.once('selection:selected', () => {
          lf.value?.closeSelectionSelect();
        });
      }
    }]);

  //节点的配置相关
  const onNodeConfig = (node: NodeConfig) => {
    const p = node.properties || {}
    p.type = node.type; //携带type属性
    
    p.id = node.id;
    showDrawer(parseConfig[node.type as ELType], p, () => {
      lf.value?.setProperties(config.form.id as string, config.form);
      config.drawerShow = false;
    });

  }

  lf.value.addMenuConfig({
    nodeMenu: [
      {
        text: '配置',
        callback(node: NodeConfig) {
          onNodeConfig(node);
        }
      },
    ],
  })
  lf.value.on("node:dbclick", (e: any) => {
    const node = e.data;
    onNodeConfig(node);
  })
  const edgeForm = ref({ value: "" })
  lf.value.on("edge:dbclick", (e: any) => {
    e.e.preventDefault()
    const edge: EdgeConfig = e.data;
    const sourceNode = lf.value?.getNodeDataById(edge.sourceNodeId);
    const formConfig = getEdgeForm(sourceNode!)
    edgeForm.value.value = (typeof edge.text === "string") ? edge.text : edge.text?.value as string;
    showDrawer(formConfig, edgeForm.value, () => {
      lf.value?.deleteEdge(edge.id!)
      if ((typeof edge.text === "string") || !edge.text) {
        edge.text = edgeForm.value.value;
      } else {
        edge.text!.value = edgeForm.value.value;
      }
      lf.value?.addEdge(edge);
      config.drawerShow = false;
    })
  })

  const onChange = () => {
    const data = lf.value?.getGraphRawData() as GraphConfigData
    localStorage.setItem("data", JSON.stringify(data));
    try {
      liteFlowData.value = parse(data);
    } catch (err: any) {
      console.log(err);
      ElMessage.error(err.message)
    }
  }

  //监听画布变化，触发change方法
  lf.value.on('history:change', onChange);

  //监听拖入节点，修改id方便展示
  lf.value.on('node:dnd-add', (data) => {
    const node = data.data;
    lf.value?.deleteNode(node.id);

    const id = getId();
    node.properties.nodeId = id;
    if (node.type === ELType.AND || node.type === ELType.NOT || node.type === ELType.OR) {
      node.properties.name = node.type;
    } else {
      node.properties.name = id;
    }

    lf.value?.addNode(node);
  })

  const data = JSON.parse(localStorage.getItem("data") as string) as GraphConfigData;
  toRaw(lf.value).render(data)

  onChange();
})

const formatterData = computed(() => {
  let str = liteFlowData.value
  let reg = /(THEN|WHEN|SWITCH|to|IF)/g;
  let result: any = {};
  let currentIndex = 0, returnData: string[] = [];

  while ((result = reg.exec(str))) {
    returnData.push(str.slice(currentIndex, result.index));
    returnData.push(result[1]);
    currentIndex = result.index + result[0].length;
  }
  if (str.length > currentIndex) {
    returnData.push(str.slice(currentIndex, str.length));
  }
  console.log(returnData);
  return returnData;
})
const runParam = reactive({
  visiable:false,
  data:'',
})
const onReq = ()=>{
  runParam.visiable = true
}

const runRes = reactive({
  show:false,
  step:"",
  context:{},
})

const runChain = ()=>{
  const param:any = {}
  try{
    param.data = JSON.parse(runParam.data)
  }catch (error) {
    ElMessage.error("JSON格式错误")
    return
  }
  runParam.visiable = false

  const chain:LiteFlowChain = {
    applicationName: "demo",
    chainName: nanoid(),
    chainDesc: "test",
    elData: liteFlowData.value,
  }
  param.chain = chain
  chainService.run(param).then((res:any)=>{
    runRes.step  = res.step
    runRes.context  = res.context
    runRes.show = true
  }).catch(err=>ElMessage.error(err))
}
</script>
<style>
.home {
  width: 100%;
  height: 99vh;
  display: flex;
}
.data-box{
  border-left: 1px solid rgba(0, 0, 0, 0.1);
  background-color: #2e2e2e;
  padding: 20px;

  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.data {
  height: 500px;
  color: #f8f8f2;
}

.data .common {
  color: #e0fff0;
  /* 代码的蓝色高亮 */
}

.hightLight {
  /* color: #ff79c6; */
  color: #9eff20c9;
  /* 关键词的粉色高亮 */
  /* font-weight: bold; */
}

.operator {
  color: #ffb86c;
  /* 操作符的橙色 */
}

.function {
  color: #50fa7b;
  /* 函数名的绿色 */
}

.container {
  flex: 1;
}
</style>